//  /*******************************************************************************
//  * Author      :  ChuanQin Yu                                                   *
//  * Copyright   :  (c) ChuanQin Yu 2023-2024                                     *
//  * mail        :  ycq1014@gmail.com                                             *
//  * License     :  http://www.boost.org/LICENSE_1_0.txt                          *
//  ********************************************************************************

#include "borderlessWidget.h"

BorderlessWidget::BorderlessWidget(QWidget *parent)
    : QWidget(parent)
{
    setWindowFlags(Qt::FramelessWindowHint);
    setWindowFlag(Qt::WindowSystemMenuHint);

    // 设置鼠标跟踪，以此来编写自己无边框自定义标题栏窗口的鼠标事件
    setMouseTracking(true);

    // 点击系统状态栏最大最小化窗口
    setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint);

    // 安装事件过滤器
    QApplication::instance()->installEventFilter(this);

    init();

    // 设置connect
    connect(titleBar, &TitleBar::closeWindow, this, &QWidget::close);
    connect(titleBar, &TitleBar::minimizeWindow, this, &QWidget::showMinimized);
    connect(titleBar, &TitleBar::maximizeWindow, this, &QWidget::showMaximized);
    connect(titleBar, &TitleBar::restoreWindow, this, &QWidget::showNormal);
    // 窗口始终在最上方显示
    connect(titleBar, &TitleBar::fixedWindow, this, &BorderlessWidget::setWindowOnTop);
    connect(titleBar, &TitleBar::unFixedWindow, this, &BorderlessWidget::unsetWindowOnTop);
}

void BorderlessWidget::init()
{
    layoutMain = new QVBoxLayout(this);
    layoutContent = new QVBoxLayout();

    // 添加标题栏
    titleBar = new TitleBar(this);

    layoutMain->addWidget(titleBar);
    auto *spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
    layoutMain->addItem(spacer);
    layoutMain->addLayout(layoutContent);
    layoutMain->addItem(spacer);

    setLayout(layoutMain);
}

void BorderlessWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        isPressed = false;
        if (dir != NONE) {
            this->releaseMouse();
            this->setCursor(QCursor(Qt::ArrowCursor));
            dir = NONE;
        }
    }
}

void BorderlessWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        isPressed = true;
        if (dir != NONE)
        {
            BorderlessWidget::mouseGrabber();
        }
        else
        {
            dragPosition = event->globalPos() - this->frameGeometry().topLeft();
        }
    }
}

void BorderlessWidget::mouseMoveEvent(QMouseEvent *event)
{
    // 获取鼠标当前位置
    QPoint gloPoint = event->globalPos();
    // 获取鼠标在窗口的位置
    QRect rect = this->rect();

    QPoint tl = this->mapToGlobal(rect.topLeft());
    QPoint br = this->mapToGlobal(rect.bottomRight());

    if (!isPressed)
    {
        this->region(gloPoint);
    }
    else
    {
        if (dir != NONE) {
            QRect rMove(tl, br);
            switch (dir) {
                case LEFT:
                    if (br.x() - gloPoint.x() <= this->minimumWidth()) {
                        rMove.setX(tl.x());
                    }
                    else {
                        rMove.setX(gloPoint.x());
                    }
                    break;
                case RIGHT:
                    rMove.setWidth(gloPoint.x() - tl.x());
                    break;
                case UP:
                    if (br.y() - gloPoint.y() <= this->minimumHeight()) {
                        rMove.setY(tl.y());
                    }
                    else {
                        rMove.setY(gloPoint.y());
                    }
                    break;
                case DOWN:
                    rMove.setHeight(gloPoint.y() - tl.y());
                    break;
                case LEFTTOP:
                    if (br.x() - gloPoint.x() <= this->minimumWidth()) {
                        rMove.setX(tl.x());
                    }
                    else {
                        rMove.setX(gloPoint.x());
                    }
                    if (br.y() - gloPoint.y() <= this->minimumHeight()) {
                        rMove.setY(tl.y());
                    }
                    else {
                        rMove.setY(gloPoint.y());
                    }
                    break;
                case RIGHTTOP:
                    rMove.setWidth(gloPoint.x() - tl.x());
                    rMove.setY(gloPoint.y());
                    break;
                case LEFTBOTTOM:
                    rMove.setX(gloPoint.x());
                    rMove.setHeight(gloPoint.y() - tl.y());
                    break;
                case RIGHTBOTTOM:
                    rMove.setWidth(gloPoint.x() - tl.x());
                    rMove.setHeight(gloPoint.y() - tl.y());
                    break;
                default:
                    break;
            }
            this->setGeometry(rMove);
        }
    }
    QWidget::mouseMoveEvent(event);
}

void BorderlessWidget::changeEvent(QEvent *event)
{
    if (event->type() == QEvent::WindowStateChange)
    {
        if (this->windowState() == Qt::WindowMaximized)
        {
            setWindowStyle(true);

            event->ignore();        // 忽略事件
        }
        else
        {
            setWindowStyle(false);

            event->ignore();        // 忽略事件
        }
    }
    event->accept();                // 接受事件
}

bool BorderlessWidget::eventFilter(QObject *watched, QEvent *event)
{
    if(isMaximized())
    {
        return QWidget::eventFilter(watched, event);
    }

    // 鼠标事件

    switch (event->type())
    {
        case QEvent::MouseMove:
        {
            auto *mouseEvent = dynamic_cast<QMouseEvent *>(event);
            if (mouseEvent)
            {
                mouseMoveEvent(mouseEvent);
            }
            break;
        }
        case QEvent::MouseButtonPress:
        {
            if(watched == this) {
                auto *mouseEvent = dynamic_cast<QMouseEvent *>(event);
                if (mouseEvent) {
                    mousePressEvent(mouseEvent);
                }
            }
            break;
        }
        case QEvent::MouseButtonRelease:
        {
            if(isPressed) {
                auto *mouseEvent = dynamic_cast<QMouseEvent *>(event);
                if (mouseEvent) {
                    mouseReleaseEvent(mouseEvent);
                }
            }
            break;
        }
        default:
            break;
    }

    return QWidget::eventFilter(watched, event);
}

void BorderlessWidget::region(const QPoint &cursorGlobalPoint)
{
    QRect rect = this->rect();
    QPoint tl = this->mapToGlobal(rect.topLeft());
    QPoint br = this->mapToGlobal(rect.bottomRight());

    int x = cursorGlobalPoint.x();
    int y = cursorGlobalPoint.y();

    if(tl.x() + PADDING >= x && tl.x() <= x && tl.y() + PADDING >= y && tl.y() <= y)
    {
        this->dir = LEFTTOP;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    }
    else if(br.x() - PADDING <= x && br.x() >= x && br.y() - PADDING <= y && br.y() >= y)
    {
        this->dir = RIGHTBOTTOM;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    }
    else if(tl.x() + PADDING >= x && tl.x() <= x && br.y() - PADDING <= y && br.y() >= y)
    {
        this->dir = LEFTBOTTOM;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    }
    else if(br.x() - PADDING <= x && br.x() >= x && tl.y() + PADDING >= y && tl.y() <= y)
    {
        this->dir = RIGHTTOP;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    }
    else if(tl.x() + PADDING >= x && tl.x() <= x)
    {
        this->dir = LEFT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }
    else if(br.x() - PADDING <= x && br.x() >= x)
    {
        this->dir = RIGHT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }
    else if(tl.y() + PADDING >= y && tl.y() <= y)
    {
        this->dir = UP;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }
    else if(br.y() - PADDING <= y && br.y() >= y)
    {
        this->dir = DOWN;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }
    else
    {
        this->dir = NONE;
        this->setCursor(QCursor(Qt::ArrowCursor));
    }

}

void BorderlessWidget::setWindowStyle(bool isMaximized)
{
    if(isMaximized)
    {
        this->layoutMain->setContentsMargins(0, 0, 0, 0);
        this->layoutMain->setSpacing(0);
    }
    else
    {
        this->layoutMain->setContentsMargins(PADDING, PADDING, PADDING, PADDING);
        this->layoutMain->setSpacing(0);
    }
}

void BorderlessWidget::setContent(QWidget *contentWidget)
{
    layoutContent->addWidget(contentWidget);
}

void BorderlessWidget::setWindowOnTop()
{
    if (this->isTopLevel())
    {
        this->setWindowFlag(Qt::WindowStaysOnTopHint);
        this->show();
    }
}

void BorderlessWidget::unsetWindowOnTop()
{
    this->setWindowFlag(Qt::WindowStaysOnTopHint, false);
    this->show();
}